package com.gitee.feizns.dynamic.convert;

import com.gitee.feizns.dynamic.convert.impl.ToNumberConverter;
import com.gitee.feizns.dynamic.convert.impl.ToStringConverter;
import com.gitee.feizns.dynamic.convert.impl.ToTimeTypeConverter;
import com.gitee.feizns.dynamic.convert.impl.ToTimestampConverter;

import java.util.Comparator;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;

/**
 * <b>类型转换工具类</b>
 * @author feizns
 * @since 2019/5/19 0019
 */
public abstract class Converts {

    /**
     * 常规转换器
     */
    private static final Set<Converter<?, ?>> CONVERTERS = new TreeSet<>(priority());

    static {
        registry(new ToNumberConverter());
        registry(new ToTimeTypeConverter());
        registry(new ToTimestampConverter());
        registry(new ToStringConverter());
        registry(MethodConverterUtils::to);
    }

    /**
     * <b>将source转换为T类型的对象</b>
     * @param source 原数据对象
     * @param targetType 目标类型class
     * @param <T> 目标类型
     * @return 返回T类型的数据
     */
    @SuppressWarnings("unchecked")
    public static <T> T to(Object source, Class<T> targetType){
        if ( source != null && !targetType.isAssignableFrom(source.getClass()) ) {
            for (Converter<?, ?> tmp : CONVERTERS) {
                if ( tmp.support(source, targetType) ) {
                    Converter<Object, T> converter = (Converter<Object, T>) tmp;
                    T result = converter.to(source, targetType);
                    if ( result != null )
                        return result;
                }
            }
            return null;
        }
        return (T) source;
    }

    /**
     * <b>将source转换为T类型的对象，并配置缺省的情况</b>
     * @param source 原数据
     * @param targetType 目标类型Class对象
     * @param defaultVal 默认值
     * @param <T> 转换的目标类型
     * @return 转换成功则返回转换后的值，不成功则返回defaultVal
     */
    public static <T> T to(Object source, Class<T> targetType, T defaultVal) {
        return Optional.ofNullable(to(source, targetType)).orElse(defaultVal);
    }

    /**
     * <b>全局注册转换器</b>
     * <pre>{@code
     * registry((Converter<String, Date>) (source, targetType) -> ExUtils.ignore(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2022-01-01 12:12:21")));
     * }</pre>
     * @param converter 转换器
     */
    public static void registry(Converter<?, ?> converter) {
        CONVERTERS.add(converter);
    }

    /**
     * <b>配置原类型和目标类型的方式，注册全家转换器</b>
     * @param sourceType 源类型class
     * @param targetType 目标类型class
     * @param converter 转换器
     * @param <S> 源类型
     * @param <R> 目标类型
     */
    public static <S, R> void registry(Class<S> sourceType, Class<R> targetType, Converter<S, R> converter) {
        CONVERTERS.add(new Converter<S, R>() {
            @Override
            public R to(S source, Class<R> targetType) {
                return converter.to(source, targetType);
            }

            @Override
            public boolean support(Object source, Class<?> type) {
                return sourceType.isAssignableFrom(source.getClass()) && targetType.isAssignableFrom(type);
            }

        });
    }

    /**
     * <b>配置目标类型的方式，注册全家转换器</b>
     * @param targetType 目标类型
     * @param converter 转换器
     * @param <S> 源类型
     * @param <R> 目标类型
     */
    public static <S, R> void registry(Class<R> targetType, Converter<S, R> converter) {
        CONVERTERS.add(new Converter<S, R>() {
            @Override
            public R to(S source, Class<R> targetType) {
                return converter.to(source, targetType);
            }

            @Override
            public boolean support(Object source, Class<?> type) {
                return targetType.isAssignableFrom(type);
            }

        });
    }

    /**
     * 排序规则
     * @see #CONVERTERS
     * @see TreeSet
     * @return 返回转换器列表的排序规则
     */
    @SuppressWarnings("all")
    private static Comparator<? super Converter<?, ?>> priority() {
        return (o1, o2) -> o1.priority() < o2.priority() ? -1 : 1;
    }

}
